import os
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.openapi.utils import get_openapi
from fastapi.staticfiles import StaticFiles
from fastapi_async_sqlalchemy import SQLAlchemyMiddleware
from fastapi_pagination import add_pagination
from sqlmodel import SQLModel
from starlette.middleware.cors import CORSMiddleware
from starlette.middleware.gzip import GZipMiddleware
from api.admin.admin_router import admin_router
from api.v1.api_v1_router import api_v1_router
from conf.config import app_config, mysql_config, redis_config, mongodb_config, scheduler_config
from core.database import engine
from core.exception.exception_handler import register_exception
from core.logger import admin_logger
from core.mongodb import init_mongodb
from core.redis import redis_client, init_redis
from core.scheduler import scheduler
from middleware.access_middle import AccessMiddleware
from utils.health_check import ensure_unique_route_names
from core.mongodb import mongo_client


async def create_table():
    # 创建所有表
    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)


@asynccontextmanager
async def register_init(app: FastAPI):
    """
    启动初始化
    """
    # 创建数据库表
    if mysql_config.OPEN_MYSQL:
        await create_table()

    # 初始化数据库连接
    if mongodb_config.OPEN_MONGODB:
        await init_mongodb()

    if redis_config.OPEN_REDIS:
        await init_redis()

    if scheduler_config.OPEN_TASK:
        # 初始化定时任务
        scheduler.init()
        scheduler.start()

    admin_logger.info(f'{app_config.APP_NAME}({app_config.APP_ENV}) started successfully.')
    yield
    admin_logger.info(f'{app_config.APP_NAME}({app_config.APP_ENV}) stopped.')

    if redis_config.OPEN_REDIS:
        # 关闭 redis 连接
        await redis_client.close()

    if scheduler_config.OPEN_TASK:
        # 关闭定时任务
        scheduler.shutdown()

    if mongodb_config.OPEN_MONGODB:
        # 关闭数据库连接
        mongo_client.close()


def register_static_file(app: FastAPI):
    """
    静态文件交互开发模式, 生产使用 nginx 静态资源服务

    :param app:
    :return:
    """

    if not os.path.exists(app_config.STATIC_DIR):
        os.mkdir(app_config.STATIC_DIR)
    app.mount('/static', StaticFiles(directory=app_config.STATIC_DIR), name="static")


def register_middleware(app) -> None:
    # DB
    app.add_middleware(
        SQLAlchemyMiddleware,
        db_url=mysql_config.ASYNC_DATABASE_URI,
        commit_on_exit=True,
        engine_args={
            "echo": mysql_config.DB_ECHO,
            "pool_pre_ping": True,
            "pool_size": mysql_config.POOL_SIZE,
            "max_overflow": mysql_config.MAX_OVERFLOW,
            "pool_recycle": mysql_config.POOL_RECYCLE,
            "pool_timeout": mysql_config.POOL_TIMEOUT
        },
    )

    # 跨域
    if app_config.MIDDLEWARE_CORS:
        app.add_middleware(
            CORSMiddleware,
            allow_origins=app_config.MIDDLEWARE_CORS_ALLOW_ORIGINS,
            allow_credentials=True,
            allow_methods=app_config.MIDDLEWARE_CORS_ALLOW_METHODS,
            allow_headers=app_config.MIDDLEWARE_CORS_ALLOW_HEADERS,
        )

    # 接口访问日志
    if app_config.MIDDLEWARE_ACCESS:
        app.add_middleware(AccessMiddleware)

    # gzip
    if app_config.MIDDLEWARE_GZIP:
        app.add_middleware(GZipMiddleware)




def init_docs(app: FastAPI):
    """
    初始化文档
    :param app:
    :return:
    """

    # 定义 API 文档
    @app.get("/api/v1/docs", include_in_schema=False)
    async def api_docs():
        return get_swagger_ui_html(
            openapi_url="/api/v1/openapi.json",
            title="API Docs",
            swagger_js_url="/static/swagger/swagger-ui-bundle.js",
            swagger_css_url="/static/swagger/swagger-ui.css"
        )

    # 定义 Admin 文档
    @app.get("/admin/docs", include_in_schema=False)
    async def admin_docs():
        return get_swagger_ui_html(
            openapi_url="/admin/openapi.json",
            title="Admin Docs",
            swagger_js_url="/static/swagger/swagger-ui-bundle.js",
            swagger_css_url="/static/swagger/swagger-ui.css"
        )

    # 定义 API OpenAPI 规范
    @app.get("/api/v1/openapi.json", include_in_schema=False)
    async def get_api_openapi():
        return get_openapi(title="API V1", version="1.0.0", routes=api_v1_router.routes)

    # 定义 Admin OpenAPI 规范
    @app.get("/admin/openapi.json", include_in_schema=False)
    async def get_admin_openapi():
        return get_openapi(title="Admin", version="1.0.0", routes=admin_router.routes)


def register_router(app: FastAPI):
    """
    路由

    :param app: FastAPI
    :return:
    """
    # 管理系统接口
    app.include_router(admin_router)
    # API接口
    app.include_router(api_v1_router)

    # Extra
    ensure_unique_route_names(app)

    # 初始化文档
    app_config.APP_ENV == 'dev' and init_docs(app)


def register_page(app: FastAPI):
    """
    分页查询

    :param app:
    :return:
    """
    add_pagination(app)


def register_app():
    # FastAPI
    app = FastAPI(
        docs_url=None,
        redoc_url=None,
        lifespan=register_init
    )
    # 静态文件
    register_static_file(app)

    # 中间件
    register_middleware(app)

    # 路由
    register_router(app)

    # 分页
    register_page(app)

    # 全局异常处理
    register_exception(app)

    return app
